#include "game.h"
#include "../utils/log.h"
#include <stdbool.h>

int sort_card(const void *a, const void *b) {
    int l = *(int *)a;
    int r = *(int *)b;
    if (l == CARD_RED_JOCKER ||
        l == CARD_BLACK_JOCKER && r != CARD_RED_JOCKER) {
        return 1;
    } else if (r == CARD_RED_JOCKER ||
               r == CARD_BLACK_JOCKER && l != CARD_RED_JOCKER) {
        return -1;
    }
    return CARD_VALUE(l) - CARD_VALUE(r);
}
// 判断是否是顺子
int is_straight(CARD *cards, size_t len) {
    if (len < 5)
        return 0;
    for (size_t i = 1; i < len; ++i) {
        if (CARD_VALUE(cards[i]) != CARD_VALUE(cards[i - 1]) + 1) {
            return 0;
        }
    }
    return 1;
}

// 判断是否是连对
int is_double_sequence(CARD *cards, size_t len) {
    if (len < 6 || len % 2 != 0)
        return 0;
    for (size_t i = 0; i < len; i += 2) {
        if (CARD_VALUE(cards[i]) != CARD_VALUE(cards[i + 1]) ||
            (i > 0 && CARD_VALUE(cards[i]) != CARD_VALUE(cards[i - 2]) + 1)) {
            return 0;
        }
    }
    return 1;
}

// 判断是否是三带一
int is_three_with_one(CARD *cards, size_t len) {
    if (len != 4)
        return -1;
    // 前三张相等
    if (CARD_VALUE(cards[0]) == CARD_VALUE(cards[1]) ||
        CARD_VALUE(cards[1]) == CARD_VALUE(cards[2])) {
        return CARD_VALUE(cards[0]);
    }
    // 后三张相等
    if (CARD_VALUE(cards[1]) == CARD_VALUE(cards[2]) ||
        CARD_VALUE(cards[2]) == CARD_VALUE(cards[3])) {
        return CARD_VALUE(cards[3]);
    }
    return -1;
}

int is_four_with_pair(CARD *cards, size_t len) {
    if (len != 6) {
        return -1;
    }
    if (CARD_VALUE(cards[0]) != CARD_VALUE(cards[1])) {
        return -1;
    }
    if (CARD_VALUE(cards[1]) == CARD_VALUE(cards[2])) {
        // 判断是否是四带二
        if (CARD_VALUE(cards[2]) == CARD_VALUE(cards[3]) &&
            CARD_VALUE(cards[4]) == CARD_VALUE(cards[5])) {
            return CARD_VALUE(cards[0]);
        }
    } else if (CARD_VALUE(cards[2]) == CARD_VALUE(cards[3]) &&
               CARD_VALUE(cards[3]) == CARD_VALUE(cards[4]) &&
               CARD_VALUE(cards[4]) == CARD_VALUE(cards[5])) {
        return CARD_VALUE(cards[5]);
    }
    return -1;
}

// 判断飞机
int is_plane(CARD *cards, size_t len) {
    if (len < 6)
        return 0;
    short cnts[14];
    memset(cnts, 0, sizeof(cnts) * sizeof(short));
    for (int i = 0; i < len; i++) {
        if (CARD_IS_JOCKER(cards[i])) {
            cnts[13]++;
        }
        cnts[CARD_VALUE(cards[i])]++;
    }
    Vec(int) two;
    Vec(int) three;
    Vec(int) one;
    vec_init(&two, 0, 2);
    vec_init(&three, 0, 2);
    vec_init(&one, 0, 2);
    for (int i = 0; i < 14; i++) {
        if (cnts[i] == 2) {
            vec_append(&two, i);
        } else if (cnts[i] == 3) {
            vec_append(&three, i);
        } else if (cnts[i] == 1) {
            vec_append(&one, i);
        } else if (cnts[i] == 0) {
            continue;
        } else {
            vec_free(&two);
            vec_free(&three);
            vec_free(&one);
            return -1;
        }
    }
    if (three.len < 2) {
        vec_free(&two);
        vec_free(&three);
        vec_free(&one);
        return -1;
    }
    for (int i = 1; i < three.len; i++) {
        if (three.data[i] != three.data[i - 1] + 1) {
            vec_free(&two);
            vec_free(&three);
            vec_free(&one);
            return -1;
        }
    }
    if (two.len != 0) {
        if (one.len != 0) {
            vec_free(&two);
            vec_free(&three);
            vec_free(&one);
            return -1;
        }
        if (two.len != three.len) {
            vec_free(&two);
            vec_free(&three);
            vec_free(&one);
            return -1;
        }
        vec_free(&two);
        vec_free(&three);
        vec_free(&one);
        return ROCKET_WITH_PAIR;
    } else if (one.len != 0) {
        if (two.len != 0) {
            vec_free(&two);
            vec_free(&three);
            vec_free(&one);
            return -1;
        }
        if (one.len != three.len) {
            vec_free(&two);
            vec_free(&three);
            vec_free(&one);
            return -1;
        }
        vec_free(&two);
        vec_free(&three);
        vec_free(&one);
        return ROCKET_WITH_SINGLE;
    } else {
        vec_free(&two);
        vec_free(&three);
        vec_free(&one);
        return ROCKET;
    }
}

// 判断飞机
int get_plane_value(CARD *cards, size_t len) {
    short cnts[14];
    memset(cnts, 0, sizeof(cnts) * sizeof(short));
    for (int i = 0; i < len; i++) {
        if (CARD_IS_JOCKER(cards[i])) {
            cnts[13]++;
        }
        cnts[CARD_VALUE(cards[i])]++;
    }
    Vec(int) three;
    vec_init(&three, 0, 2);
    for (int i = 0; i < 14; i++) {
        if (cnts[i] == 3) {
            vec_append(&three, i);
        }
    }
    int ret = CARD_VALUE(three.data[0]);
    vec_free(&three);
    return ret;
}

// 获取牌型的函数实现
HAND_TYPE get_card_type(CARD *cards, size_t len) {
    if (len == 0) {
        return INVALID_TYPE;
    }
    if (len == 1)
        return SINGLE;
    qsort((void *)cards, len, sizeof(int), sort_card);
    if (len == 2) {
        if (cards[0] == CARD_BLACK_JOCKER && cards[1] == CARD_RED_JOCKER)
            return JOCKER_BOMB;
        if (CARD_VALUE(cards[0]) == CARD_VALUE(cards[1]))
            return PAIR;
    }
    if (len == 3) {
        if (CARD_VALUE(cards[0]) == CARD_VALUE(cards[2]))
            return THREE;
    }
    if (len == 4) {
        if (CARD_VALUE(cards[0]) == CARD_VALUE(cards[3]))
            return BOMB;
        if (is_three_with_one(cards, len))
            return THREE_WITH_ONE;
    }
    if (len == 5) {
        // 三带一对
        if (CARD_VALUE(cards[0]) == CARD_VALUE(cards[2]) &&
            CARD_VALUE(cards[3]) == CARD_VALUE(cards[4])) {
            return THREE_WITH_PAIR;
        } else if (CARD_VALUE(cards[2]) == CARD_VALUE(cards[4]) &&
            CARD_VALUE(cards[0]) == CARD_VALUE(cards[1])){
            return THREE_WITH_PAIR;
        }
    }
    // 五张及以上
    if (is_straight(cards, len))
        return STRAIGHT;
    if (is_double_sequence(cards, len))
        return DOUBLE_SEQUENCE;
    if (len >= 6) {
        int type = is_plane(cards, len);
        if (type != -1) {
            return type;
        }
    }
    return INVALID_TYPE;
}

// 比较两手牌的大小
bool compare_cards(CARD *prev_cards, size_t prev_len, CARD *new_cards,
                   size_t new_len) {

    HAND_TYPE prev_type = get_card_type(prev_cards, prev_len);
    HAND_TYPE new_type = get_card_type(new_cards, new_len);

    log_info("prev_type: %d, new_type: %d", prev_type, new_type);

    if (prev_len == 0) {
        return new_type != INVALID_TYPE;
    }
    if (new_type == INVALID_TYPE || prev_type == INVALID_TYPE) {
        return false;
    }
    if (new_type == JOCKER_BOMB) {
        return true;
    }
    if (prev_type == JOCKER_BOMB) {
        return false;
    }
    // 处理炸弹
    if (new_type == BOMB && prev_type != BOMB) {
        return true;
    }
    if (prev_type == BOMB && new_type != BOMB) {
        return false;
    }
    if (prev_type == BOMB && new_type == BOMB) {
        return CARD_VALUE(new_cards[0]) > CARD_VALUE(prev_cards[0]);
    }
    // 牌型不同且不涉及炸弹和王炸的情况
    if (new_type != prev_type) {
        return false;
    }
    // 单牌
    if (new_type == SINGLE) {
        if (CARD_IS_JOCKER(new_cards[0])) {
            if (!CARD_IS_JOCKER(prev_cards[0])) {
                return true;
            } else {
                return CARD_VALUE(new_cards[0]) > CARD_VALUE(prev_cards[0]);
            }
        }
    }
    if (new_type == ROCKET || new_type == ROCKET_WITH_PAIR ||
        new_type == ROCKET_WITH_SINGLE) {
        return get_plane_value(new_cards, new_len) >
               get_plane_value(prev_cards, prev_len);
    }
    // 牌型相同的情况下比较大小
    return CARD_VALUE(new_cards[0]) > CARD_VALUE(prev_cards[0]);
}

game_t *game_init(int id, char *room_name) {
    game_t *game = (game_t *)malloc(sizeof(game_t));
    game->room_name = strdup(room_name);
    vec_init(&game->cards, 0, 20);
    for (int i = 0; i < 3; i++) {
        game->players[i].status = PLAYER_STATUS_NONE;
        vec_init(&game->players[i].handcard, 0, 20);
    }
    pthread_cond_init(&game->cond, NULL);
    pthread_mutex_init(&game->mutex, NULL);
    game->id = id;
    game->status = GAME_STATUS_WAIT_PLAYER;
    game->player_count = 1;
    game->who = -1;
    game->who_load = -1;
    game->count = 0;
    for (int i = 0; i < 3; i++) {
        game->players[i].id = -1;
    }
    return game;
}

bool is_allready(game_t *game) {
    if (game->player_count < 3) {
        return false;
    }
    for (int i = 0; i < 3; i++) {
        if (game->players[i].status != PLAYER_STATUS_READY) {
            return false;
        }
    }
    log_debug("all ready");
    return true;
}

void game_start(game_t *game) {
    // 等待玩家准备
    log_debug("game: wait allready");
    pthread_mutex_lock(&game->mutex);
    while (!is_allready(game)) {
        pthread_cond_wait(&game->cond, &game->mutex);
        log_debug("game: check ready");
    }
    log_debug("game: all people ready");
    game->status = GAME_STATUS_START;
    for (int i = 0; i < game->player_count; i++) {
        game->players[i].status = PLAYER_STATUS_GAMEING;
    }
    pthread_mutex_unlock(&game->mutex);
    int *cards = (int *)malloc(sizeof(int) * CARD_NUMBER);
    for (int i = 0; i < CARD_NUMBER; i++) {
        cards[i] = i;
    }
    // 洗牌
    srand((unsigned)time(NULL));
    // 洗牌算法
    for (int i = 0; i < CARD_NUMBER; i++) {
        int index = i + (rand() % (CARD_NUMBER - i));
        int temp = cards[i];
        cards[i] = cards[index];
        cards[index] = temp;
    }
    // 发牌
    int p = 0;
    pthread_mutex_lock(&game->mutex);
    for (int i = 0; i < 54; i++) {
        printf("%d ", cards[i]);
    }
    printf("\n");
    for (int i = 0; i < 3; i++) {
        vec_clear(&game->players[i].handcard);
        // 地主牌
        for (int j = 0; j < 17; j++) {
            vec_append(&game->players[i].handcard, cards[p++]);
        }
    }
    // 排序
    for (int i = 0; i < 3; i++) {
        qsort(game->players[i].handcard.data, game->players[i].handcard.len,
              sizeof(int), sort_card);
    }
    // 地主牌
    for (int i = 0; i < 3; i++) {
        game->cards.data[i] = cards[p++];
    }
    for (int i = 0; i < 3; i++) {
        printf("%d ", game->cards.data[i]);
    }
    printf("\n");
    free(cards);
    int idx = rand() % game->player_count;
    game->who = idx;
    log_info("game: start, who is %d", idx);
    game_play(game);
}

void game_end(game_t *game) {
    game->status = GAME_STATUS_WAIT_PLAYER;
    game->who = -1;
    game->who_load = -1;
    for (int i = 0; i < game->player_count; i++) {
        // 玩家状态重置
        game->players[i].status = PLAYER_STATUS_NONE;
    }

    pthread_mutex_unlock(&game->mutex);
    game_start(game);
}

void game_play(game_t *game) {
    // 进入叫地主状态
    game->status = GAME_STATUS_CALLLOAD;
    for (size_t i = 0; i < 3; i++) {
        game->rob_status[i] = ROB_LOAD_NONE;
    }
    log_debug("waiting call load");
    // 等待叫地主，叫地主状态,询问每个人
    while (game->rob_status[0] == ROB_LOAD_NONE ||
           game->rob_status[1] == ROB_LOAD_NONE ||
           game->rob_status[2] == ROB_LOAD_NONE) {
        pthread_cond_wait(&game->cond, &game->mutex);
        // 下一个
        game->who = (game->who + 1) % 3;
    }
    // 如果没有人叫地主重新洗牌
    if (game->rob_status[0] == ROB_LOAD_PASS &&
        game->rob_status[1] == ROB_LOAD_PASS &&
        game->rob_status[2] == ROB_LOAD_PASS) {
        log_debug("no people call, restart");
        game_start(game);
        return;
    }
    // 谁第一个叫地主
    game->status = GAME_STATUS_ROBLOAD;
    int call = 0;
    for (size_t i = 0; i < 3; i++) {
        if (game->rob_status[i] == ROB_LOAD_CALL) {
            call = i;
            break;
        }
    }
    for (size_t i = 0; i < 3; i++) {
        int idx = (i + call) % 3;
        if (game->rob_status[idx] == ROB_LOAD_ROB) {
            // 询问call 是否同意
            game->who = call;
            pthread_cond_wait(&game->cond, &game->mutex);
            if (game->rob_status[call] == ROB_LOAD_ROB) {
                // 把地主给call
                game->who_load = call;
                break;
            } else {
                game->who_load = idx;
                break;
            }
        }
    }

    log_debug("who load %d", game->who_load);
    // 拿地主牌
    int idx = game->who_load;
    player_t *load = &game->players[idx];
    for (int i = 0; i < 3; i++) {
        vec_append(&load->handcard, game->cards.data[i]);
    }
    // 地主牌排序
    qsort(load->handcard.data, load->handcard.len, sizeof(int), sort_card);
    game->cards.len = 0;
    // 地主出牌
    game->who = game->who_load;
    game->last_who = game->who_load;
    game->status = GAME_STATUS_GAMEING;
    log_debug("game start");
    // 游戏开始
    // 等待游戏结束
    while (game->status == GAME_STATUS_GAMEING) {
        pthread_cond_wait(&game->cond, &game->mutex);
    }
    log_debug("game end");
    // 游戏结束
    game_end(game);
}

/**
 * 游戏出牌, 出牌成功返回空，失败返回失败原因
 * @param game 游戏对象
 * @param player_id 玩家id
 * @param card 出牌
 */
char *game_play_card(game_t *game, player_t *player, CARD *card, int cardsize) {
    // 玩家选好牌后，在点出牌时与上家出的牌比较
    CARD *last_card = game->cards.data; // 上家出的牌
    // 如果上家也是自己或比上家的牌大，那点击出牌就有效，否则无效
    if ((game->last_who == game->who &&
         get_card_type(card, cardsize) != INVALID_TYPE) ||
        compare_cards(last_card, game->cards.len, card, cardsize)) {
        // 有效后，从玩家手牌中移除该牌
        pthread_mutex_lock(&game->mutex);
        Vec(int) newhandcard;
        vec_init(&newhandcard, 0, 10);
        for (int i = 0; i < player->handcard.len; i++) {
            bool flag = true;
            for (int j = 0; j < cardsize; j++) {
                if (player->handcard.data[i] == card[j]) {
                    flag = false;
                    break;
                }
            }
            if (flag) {
                // 出牌中没有，保留手牌
                vec_append(&newhandcard, player->handcard.data[i]);
            }
        }
        vec_clear(&player->handcard);
        vec_extend(&player->handcard, &newhandcard.data, newhandcard.len);

        // 更新上家牌
        vec_clear(&game->cards);
        for (int i = 0; i < cardsize; i++) {
            vec_append(&game->cards, card[i]);
        }
        // 上次出牌玩家
        game->last_who = game->who;
        // 更新出牌玩家
        game->who = (game->who + 1) % 3;
        pthread_mutex_unlock(&game->mutex);
        vec_free(&newhandcard);
        log_info("play card success");
        return NULL;
    }
    return "invalid card";
}

/**
 * 游戏销毁
 * @param game 游戏对象
 */
void game_destory(game_t *game) {
    // 销毁线程同步锁
    pthread_cond_destroy(&game->cond);
    pthread_mutex_destroy(&game->mutex);
    free(game->room_name);
    free(game->cards.data);
    free(game);
}

void *game_thread_func(void *arg) {
    game_t *game = (game_t *)arg;
    // 游戏开始
    game_start(game);
    return NULL;
}

cJSON *player_to_json(player_t *player) {
    cJSON *json_player = cJSON_CreateObject();
    // log_info("player to json success");
    cJSON_AddNumberToObject(json_player, "id", player->id);
    // log_info("player to json success");
    cJSON_AddStringToObject(json_player, "username", player->username);
    // log_info("player to json success");
    cJSON_AddNumberToObject(json_player, "status", player->status);
    // log_info("player to json success");
    cJSON_AddNumberToObject(json_player, "cardsize", player->handcard.len);
    // log_info("player to json success");
    return json_player;
}

cJSON *game_to_json(game_t *game) {
    cJSON *json_game = cJSON_CreateObject();
    cJSON_AddNumberToObject(json_game, "id", game->id);
    cJSON_AddStringToObject(json_game, "room_name", game->room_name);
    cJSON_AddNumberToObject(json_game, "status", game->status);
    cJSON_AddNumberToObject(json_game, "player_count", game->player_count);
    cJSON_AddNumberToObject(json_game, "who", game->who);
    cJSON_AddNumberToObject(json_game, "who_load", game->who_load);
    // log_info("rob status");
    cJSON *json_rob_status = cJSON_CreateArray();
    for (int i = 0; i < 3; ++i) {
        cJSON_AddItemToArray(json_rob_status,
                             cJSON_CreateNumber(game->rob_status[i]));
    }
    cJSON_AddItemToObject(json_game, "rob_status", json_rob_status);

    cJSON_AddNumberToObject(json_game, "count", game->count);

    // log_info("game card");
    cJSON *json_cards = cJSON_CreateArray();
    for (int i = 0; i < game->cards.len; ++i) {
        cJSON_AddItemToArray(json_cards,
                             cJSON_CreateNumber(game->cards.data[i]));
    }
    cJSON_AddItemToObject(json_game, "cards", json_cards);

    // log_info("game player");
    cJSON *json_players = cJSON_CreateArray();
    // log_info("game player count:%d", game->player_count);
    // log_info("room: %s", game->room_name);
    for (int i = 0; i < 3; ++i) {
        if (game->players[i].id != -1) {
            cJSON_AddItemToArray(json_players,
                                 player_to_json(&game->players[i]));
        } else {
            cJSON *player = cJSON_CreateObject();
            cJSON_AddNumberToObject(player, "id", -1);
            cJSON_AddItemToArray(json_players, player);
        }
    }
    cJSON_AddItemToObject(json_game, "players", json_players);

    return json_game;
}